package com.upcode.weighing.oauthres;

import com.fasterxml.jackson.databind.ObjectMapper;
import io.jsonwebtoken.*;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.Map;

/**
 * @author ZYW
 * @date 2018/2/2
 */
@Configuration
@EnableResourceServer
//开启基于方法的声明式权限控制
@EnableGlobalMethodSecurity(prePostEnabled = true)
//去除spring的http基本验证,作用相当于springboot2.0之前的security.basic.enabled=false
@EnableAutoConfiguration(exclude = {
//        org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration.class
})

public class ResourceServerConfig extends ResourceServerConfigurerAdapter {

    public static String USER_STATUS_KEY = "USER_STATUS_KEY:";

    private static final String JWT_TOKE_KEY = "mydao@safe#auth$";

    private static final Logger LOGGER = LoggerFactory.getLogger(ResourceServerConfig.class);

    @Autowired
    private StringRedisTemplate stringRedisTemplate;
//
//    @Value("${isprod}")
//    private Boolean isprod;

    private static String[] AUTH_WHITELIST = new String[]{

        // -- swagger ui
        "/swagger-resources/**",
        "/swagger-ui.html",
        "/doc.html",
        "/v2/api-docs",
            "/webjars/**",
            //"/**"
    };

    private String [] getAuthWhitelist(){

        //在缓存里取出白名单
        /*List<String> whiteList = stringRedisTemplate.opsForList().range("AUTH_WHITELIST",0,stringRedisTemplate.opsForList().size("AUTH_WHITELIST")-1);
        String[] AUTH_WHITELIST = new String[whiteList.size()];
        whiteList.toArray(AUTH_WHITELIST);*/

        LOGGER.debug("===================白名单===================");

        /*if ( Boolean.FALSE.equals(isprod) ){
            AUTH_WHITELIST[AUTH_WHITELIST.length-1]="/**";
        }*/

        return AUTH_WHITELIST;
    }

    @Override
    public void configure(HttpSecurity http) throws Exception {

        http.csrf().disable()
            .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
            .and()
            .exceptionHandling()
            .authenticationEntryPoint((request, response, authException) -> {
                Map<String,String> map = getResponseMap(response,"登陆已过期，请重新登陆");
                try {
                    LOGGER.info(new ObjectMapper().writeValueAsString(map));
                    response.getOutputStream().write(new ObjectMapper().writeValueAsString(map).getBytes());
                } catch (Exception e) {
                    throw new ServletException();
                }
            })
            .and()
            .authorizeRequests().antMatchers(getAuthWhitelist()).permitAll()
            .anyRequest().authenticated()
            .and()
            .httpBasic().disable();
    }
    @Override
    public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
        resources.authenticationEntryPoint((request,response,authException) -> {
            String resultToken;
            String token = request.getHeader("Authorization");
            if(StringUtils.isNotEmpty(token)){
                boolean b = token.startsWith("B");
                if(b){
                    resultToken = token.split("Bearer")[1].trim();
                }else{
                    resultToken = token.split("bearer")[1].trim();
                }
            }else{
                resultToken = request.getParameter("access_token");
            }
            String message;
            try {
                Claims claims = Jwts.parser().setSigningKey(JWT_TOKE_KEY.getBytes("UTF-8")).parseClaimsJws(resultToken).getBody();
                String username = null;
                if(claims.get("user_name") != null ){
                    username = String.valueOf(claims.get("user_name"));
                }else{
                    username = String.valueOf(claims.get("username"));
                }

                String type = stringRedisTemplate.boundValueOps(USER_STATUS_KEY+username).get();
                stringRedisTemplate.delete(USER_STATUS_KEY+username);
                if(StringUtils.equals("1",type)) {
                    message ="用户被禁用";
                } else if(StringUtils.equals("2",type)) {
                    message ="用户已在其他终端登陆";
                } else {
                    message ="登陆已过期，请重新登陆";
                }
            } catch (ExpiredJwtException e) {
                message ="登陆已过期，请重新登陆";
            } catch (UnsupportedJwtException e) {
                LOGGER.error("token非法",e);
                message ="登陆已过期，请重新登陆";
            } catch (MalformedJwtException e) {
                LOGGER.error("jwt未能正常被构造,token值:"+token,e);
                message ="非法登陆";
            }
//            catch (SignatureException e) {
//                LOGGER.error("签名计算失败",e);
//                message ="非法登陆";
//            }
            catch (IllegalArgumentException e) {
                LOGGER.error("token参数非法",e);
                message ="非法登陆";
            }
            Map<String,String> map = getResponseMap(response,message);
            try {
                LOGGER.info(new ObjectMapper().writeValueAsString(map));
                response.getOutputStream().write(new ObjectMapper().writeValueAsString(map).getBytes());
            } catch (Exception e) {
                throw new ServletException();
            }
        });
    }


    private Map getResponseMap(HttpServletResponse response, String message){
        Map<String,String> map = new HashMap<>();
        map.put("code", "401");
        map.put("message", message);
        map.put("timestamp", String.valueOf(System.currentTimeMillis()));
        response.setContentType("application/json;charset=UTF-8");
        response.setHeader("Access-Control-Allow-Origin","*");
        response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
        return  map;
    }

}
